﻿/**
 * Created by Richard Radlherr.
 * Date: 25.06.2006 02:41
 */
using System;
using System.Collections.Generic;
using CsGL;
using CsGL.OpenGL;
using TagTool.Core;
using TagTool.OpenGL;
using TagTool.GraphicTypes;

namespace TagTool.Nodes.Graphic
{

	public class Movement3 : BaseNode
	{
		private InputSlot shape;
		private InputSlot scene;
		
		private InputSlot direction;
		private InputSlot speed;
		private InputSlot spin;
		private InputSlot zoom;
		
		private PointD dirOld = PointD.Origin;
		private double speedOld = 2.0;
		private double spinOld = 0.0;
		private PointD zoomOld = PointD.Origin;
		
		private PointD dirsOld = PointD.Origin;
		private double speedsOld = 2.0;
		private double spinsOld = 0.0;
		private PointD zoomsOld = PointD.Origin;
		
		private Shape shapeOld;
		private TagTool.GraphicTypes.Scene sceneOld;
		
		private bool applyLastOld = false;
		private bool applyAllOld = false;
		
		private InputSlot radius;
		
		private InputSlot channel;
		private InputSlot applyLast;
		private InputSlot applyAll;

		public Movement3()
		{
			Name = "Movement";

			direction = new InputSlot(this, "Direction", PointD.Origin);
			speed = new InputSlot(this, "Speed", 2.0);
			channel = new InputSlot(this, "Channel", false);
			
			applyAll = new InputSlot(this, "Apply for all", false);
			applyLast = new InputSlot(this, "Apply for last", false);
			
			spin = new InputSlot(this, "Spin", 0.0);
			radius = new InputSlot(this, "Radius", 10.0);
			zoom = new InputSlot(this, "Zoom", PointD.Origin);
			
			shape = new InputSlot(this, "Input Shape", new Shape());
			scene = new InputSlot(this, "Input Scene", new TagTool.GraphicTypes.Scene());
	
			direction.ParseCallback = ParseHelper.ParseVector;
			zoom.ParseCallback = ParseHelper.ParseVector;
			spin.ParseCallback = ParseHelper.ParseDouble;
			radius.ParseCallback = ParseHelper.ParseDouble;
			speed.ParseCallback = ParseHelper.ParseDouble;
			
			shapeOld = (Shape)shape.Value;
			sceneOld = (TagTool.GraphicTypes.Scene)scene.Value;
		}
		
		private void ApplyAll()
		{
			foreach(Shape s in ((TagTool.GraphicTypes.Scene)scene.Value).Shapes)
			{
				s.Zoom = zoomsOld;
				s.Speed = speedsOld;
				s.Direction = dirsOld;
				s.Spin = spinsOld;
				s.MoveState = MoveState.Swarm;
			}
		}
		
		private void ApplyLast()
		{
			List<Shape> shapes = ((TagTool.GraphicTypes.Scene)scene.Value).Shapes;
			if (shapes.Count > 0)
			{
				Shape s = shapes[shapes.Count - 1];
				s.Zoom = zoomsOld;
				s.Speed = speedsOld;
				s.Direction = dirsOld;
				s.Spin = spinsOld;
			}
		}
		
		private void UpdateShape()
		{
			if (shapeOld.MoveState == MoveState.Single)
			{
				shapeOld.Zoom = zoomOld + (PointD)zoom.Value;
				shapeOld.Speed = speedOld + (double)speed.Value;
				shapeOld.Direction = dirOld + (PointD)direction.Value;
				shapeOld.Spin = spinOld + (double)spin.Value;
			}
			else
			{
				shapeOld.Zoom = zoomsOld + (PointD)zoom.Value;
				shapeOld.Speed = speedsOld + (double)speed.Value;
				shapeOld.Direction = dirsOld + (PointD)direction.Value;
				shapeOld.Spin = spinsOld + (double)spin.Value;
			}
		}

		private void UpdateSelected()
		{
			shapeOld.Zoom = zoomOld;
			shapeOld.Speed = speedOld;
			shapeOld.Direction = dirOld;
			shapeOld.Spin = spinOld;
		}

		public override void Update(Object sender)
		{
			if (shapeOld != shape.Value)
			{
				if (shapeOld.MoveState == MoveState.Single)
				{
					shapeOld.Direction = dirOld;
					shapeOld.Speed = speedOld;
					shapeOld.Spin = spinOld;
					shapeOld.Zoom = zoomOld;
				}
				else if (shapeOld.MoveState == MoveState.Swarm)
				{
					shapeOld.Direction = dirsOld;
					shapeOld.Speed = speedsOld;
					shapeOld.Spin = spinsOld;
					shapeOld.Zoom = zoomsOld;
				}

				shapeOld = (Shape)shape.Value;
				
				zoomOld = shapeOld.Zoom;
				speedOld = shapeOld.Speed;
				spinOld  = shapeOld.Spin;
				dirOld = shapeOld.Direction;
				
				zoom.Value = zoomOld;
				speed.Value = speedOld;
				spin.Value = spinOld;
				direction.Value = dirOld;
			}
			
			if ((bool)TriggerIn.Value)
			{
				zoomOld = (PointD)zoom.Value;
				speedOld = (double)speed.Value;
				spinOld  = (double)spin.Value;
				dirOld = (PointD)direction.Value;
				shapeOld.MoveState = MoveState.Single;
				UpdateShape();
			}
			else if ((bool)channel.Value)
			{
				zoomsOld = (PointD)zoom.Value;
				speedsOld = (double)speed.Value;
				spinsOld  = (double)spin.Value;
				dirsOld = (PointD)direction.Value;
				ApplyAll();
			}
			else 
			{
				UpdateShape(); // TODO: -> möglicherweise ursache doppelter geschw.
			}
			
			if ((bool)applyAll.Value != applyAllOld)
			{
				applyAllOld = (bool)applyAll.Value;
    			ApplyAll();
			}
			else if ((bool)applyLast.Value != applyLastOld)
			{
				applyLastOld = (bool)applyLast.Value;
				ApplyLast();
			}

		}

		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Direction
		{
			get { return direction; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Speed
		{
			get { return speed; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Spin
		{
			get { return spin; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Zoom
		{
			get { return zoom; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Radius
		{
			get { return radius; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Shape
		{
			get { return shape; }
		}

		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Scene
		{
			get { return scene; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot Channel
		{
			get { return channel; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot ApplyForAll
		{
			get { return applyAll; }
		}
		
		[NodeAttribute(SlotType.Input, Show = true)]
		public InputSlot ApplyForLast
		{
			get { return applyLast; }
		}
	}
}
